package watki;

import java.io.File;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.TreeSet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import algorytmy.*;

public class ManagerWatkow {
	private static ManagerWatkow manager;
	private static StringBuilder wynikTekst = new StringBuilder();
	private CountDownLatch cd = null;
	private int maxWatkow;
	private int ileWatkow;
	private ManagerWatkow(){
		maxWatkow = dostepneProcesory();
	}
	
	public static ManagerWatkow manager(){
		if(manager == null)
			manager = new ManagerWatkow();
		return manager;
	}
	
	public int ileWatkow(){
		return ileWatkow;
	}
	
	//ACHTUNG
	// Jezeli wzorzec jest wiekszy niz tekst bedzie sialo wyjatkami
	public TreeSet<Integer> start(Algorytmy al, String wzorzec, String tekst,int ileW) throws Exception {
		ileWatkow = ileW;
		if(ileWatkow > maxWatkow || ileWatkow < 0 )
			throw new Exception("Nieprawidłowa liczba Wątków!\n Max " + maxWatkow);
		if(cd != null && cd.getCount() > 0){
			throw new Exception("Przetwarzanie jeszze się nie zakończyło!!!");
		}
		
		
		ExecutorService exe = Executors.newCachedThreadPool();
		
		int start = 0,koniec = 0;

		//nie oplaca sie dzielic takiego tekstu
		if(tekst.length() == wzorzec.length())
			ileWatkow = 1;
		//char per thread
		int cpt = tekst.length()/ileWatkow;
		if(cpt < wzorzec.length()){
			cpt = wzorzec.length();
			ileWatkow = tekst.length()/wzorzec.length();
		}
		cd = new CountDownLatch(ileWatkow);

		LinkedList<WyszukiwanieWzorca> watki = new LinkedList<WyszukiwanieWzorca>();
		
		int move = wzorzec.length();
		for(int i = 0; i < ileWatkow; i++){
			koniec += cpt;
			if( (koniec  + move) > tekst.length()){
				koniec = tekst.length();
				move = 0;
			}
			watki.add(wyszukiwanieWzorca(al, wzorzec, tekst, start, koniec + move));
			exe.execute(watki.getLast());
			start = koniec;
				
		}
		
		cd.await();
		
		TreeSet<Integer> wynik = new  TreeSet<Integer>();
		for(WyszukiwanieWzorca wz: watki)
			wynik.addAll(wz.getPozycje());
		
		int linia = 1;
		
		Scanner in = new  Scanner(tekst);
		String sep = System.getProperty("line.separator");
		String dopisek = wynik.size()==1?"raz":"razy";
		wynikTekst.append("Tekst " + wzorzec + " wystąpiło " + wynik.size() + " " + dopisek+sep);
		int currentLenght;
		String line = in.nextLine();
		currentLenght = line.length();
		for(Integer pozycja : wynik){
			while((pozycja - linia + 2) > currentLenght && in.hasNextLine()){
				line = in.nextLine();
				linia++;
				currentLenght += line.length();
			}
			wynikTekst.append("linia " + linia + " znak " + (pozycja - linia + 2)+sep);

		}
		return wynik;
	}
	
	public static StringBuilder getWynik(){
		return wynikTekst;
	}
	
	public static int dostepneProcesory(){
		Runtime run = Runtime.getRuntime();
		return run.availableProcessors();
	}
	
	private  WyszukiwanieWzorca wyszukiwanieWzorca(Algorytmy al,String wzorzec,String tekst, int start, int koniec){
		
		switch(al){
		case NAIWNY:
			return new Naiwny(wzorzec.toCharArray(), tekst.toCharArray(), start, koniec,cd);
		case BOYER_MOORE:
			return new BoyerMoore(wzorzec.toCharArray(), tekst.toCharArray(), start, koniec, cd);
		case KNUTH_MORRIS_PRATT:
			return new KnuthMorrisPratt(wzorzec.toCharArray(), tekst.toCharArray(), start, koniec, cd);
		case KARP_RABIN:
			return new KarpRabin(wzorzec.toCharArray(), tekst.toCharArray(), start, koniec, cd);
		case MORRIS_PRATT:
			return new MorrisPratt(wzorzec.toCharArray(), tekst.toCharArray(), start, koniec, cd);
		
		}
		return null;
	}

}
